#! /usr/bin/env python
# -*- coding: utf-8 -*-
"""KIEL2 data format

Copyright (c) 2011-2013 Christian T. Steigies <steigies@physik.uni-kiel.de>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

This module offers functions to read NM data in ASCII format as used in KIEL
and return data in the format as used by NMDB."""

__author__ = "Christian T. Steigies <steigies@physik.uni-kiel.de>"
__license__ = "GPL License"

from datetime import datetime, date, time
from calendar import monthrange
import MySQLdb  # python-mysqldb

from nmdb.station.station_data import check_data, check_pressure
from nmdb.tools.datetool import str2datetime, valid_date
from nmdb.tools.configtool import parse_options, parse_config
from nmdb.editor.median import median

kiel2_station = ["kiel2"]

# move to class, as well cr_min/max, p_min/max, pressure correction factors
base_counts = [30220, 35780, 36960, 37362, 37020, 31690,
               32550, 36785, 38000, 37284, 36826, 32270,
               32200, 37003, 37685, 37910, 37125, 31030]

## --------------------------------------------------------------------------
def read_rt(options, station, data_type, year, month, day):
    """read realtime data

    options     verbose, dryrun, ...
    station     station short name, must be valid station
    data_type   "1m", "1h", "env", "meta"
    year        integer (1950-9999), may not be None
    month       integer (1-12), if None, read month 1-12
    day         integer (1-31), if None, read day 1-31

    return list of values in nmdb format
    """

    if station in kiel2_station:
        pass
    else:
        raise ValueError  # wrong station

    value = []
    if valid_date(year, month, day):
        value = read_kiel2(options, station, data_type, year, month, day)

    return value

## --------------------------------------------------------------------------
def read_rev(options, station, data_type, year, month, day):
    """read revised data

    options     verbose, dryrun, ...
    station     station short name, must be valid station
    data_type   "1m", "1h", "env", "meta"
    year        integer (1950-9999), may not be None
    month       integer (1-12), if None, read month 1-12
    day         integer (1-31), if None, read day 1-31

    return list of values in nmdb format
    """

    if station in kiel2_station:
        pass
    else:
        raise ValueError  # wrong station

    value = []
    if valid_date(year, month, day):
        # TODO revised data in SQLite or separate database?
        value = read_kiel2(options, station, data_type, year, month, day)

    return value

## --------------------------------------------------------------------------
def read_kiel2(options, station, data_type, year=None, month=None, day=None, hour=None):
    # read_bin data into a bin object?
    # run median editor? on bon object, receive countrates
    # pressure correct countrate, return data in sqlite object

    if station != "kiel2":
        raise ValueError  # illegal station
    mode = "nmdadb"
    (username, password, hostname, dbname, portnumber) = parse_config(options.rcfile, station, mode)

    con = MySQLdb.connect(host=hostname, port=portnumber, db=dbname, user=username, passwd=password)
    cursor = con.cursor()

    if data_type in ["1h"]:
        raise ValueError  # 1h not yet implemented
        data = read_1h(options, cursor, year, month, day, hour)
    elif data_type in ["1m", "ori"]:
        data = read_1m(options, cursor, year, month, day, hour)
    else:
        raise ValueError  # illegal data_type

    return data

## --------------------------------------------------------------------------
def read_1m(options, cursor, year, month, day, hour):
    myinterval = 60
    data = []
    tubes = len(base_counts)
    base_eff = [1.] * tubes

    rows = read_bin(options, cursor, year, month, day, hour)
    for row in rows:
        #print row
        nt = row[1:tubes+1]  # k channels in counts per resolution (minute)
        pressure_mbar = row[tubes+1] / 100.  # in mbar
        #print nt
        (summa, ne, et) = median(tubes, base_counts, base_eff, nt)
        #print summa, ne, et
        #print row[0]
        mydatetime = str2datetime(str(row[0]))
        uncorrected = summa / 60.
        corrected = corrected_for_pressure(uncorrected, pressure_mbar)
        corr_eff = corrected_for_efficiency(corrected)
        
        # round data to three digits, pressure to two
        uncorrected = round(uncorrected, 3)
        pressure_mbar = round(pressure_mbar, 2)
        corrected = round(corrected, 3)
        corr_eff = round(corr_eff, 3)
        
        # basic data quality checks
        # TODO use station object to set ranges
        uncorr = check_data(uncorrected, cr_min=10., cr_max=10000.)
        press = check_pressure(pressure_mbar, p_min=950., p_max=1100.)
        corr = check_data(corrected, cr_min=10., cr_max=10000.)
        ceff = check_data(corr_eff, cr_min=10., cr_max=10000.)
        # order as in NMDB
        data.append([mydatetime, myinterval, uncorr, ceff, corr, press])
        if options.verbose:
            print mydatetime, myinterval, uncorr, ceff, corr, press

    return data

## --------------------------------------------------------------------------
def read_1h(options, cursor, year, month, day, hour):

    return None

## --------------------------------------------------------------------------
def read_bin(options, cursor, year, month, day, hour):

    if options.verbose > 0:
        print year, month, day, hour

    # TODO always reading 1 day at a time?
    if year is None:
        raise ValueError  # year has to be specified
    elif month is None:  # read one year
        startdate = date(year, 1, 1)
        starttime = time(0, 0, 0)
        stoppdate = date(year, 12, 31)
        stopptime = time(23, 59, 59)
    elif day is None:  # read one month
        startdate = date(year, month, 1)
        starttime = time(0, 0, 0)
        (weekday, day_max) = monthrange(year, month)
        stoppdate = date(year, month, day_max)
        stopptime = time(23, 59, 59)
    elif hour is None:  # read one day
        startdate = date(year, month, day)
        starttime = time(0, 0, 0)
        stoppdate = startdate
        stopptime = time(23, 59, 59)
    else:  # read one hour
        startdate = date(year, month, day)
        starttime = time(hour, 0, 0)
        stoppdate = startdate
        stopptime = time(hour, 59, 59)
    start = datetime.combine(startdate, starttime)
    stopp = datetime.combine(stoppdate, stopptime)

    # use columns in the order of NM64 BIN format
    cols = "start_date_time, ch01, ch02, ch03, ch04, ch05, ch06, ch07, ch08, ch09, ch10, ch11, ch12, ch13, ch14, ch15, ch16, ch17, ch18, atmPressure, temp_1, temp_2, hv1, hv2, hv3, 0, 0"

    querystring = ("SELECT %s FROM binTable WHERE start_date_time >= \"%s\" AND "
                       "start_date_time <= \"%s\" ORDER BY start_date_time ASC;"
                       ) % (cols, start, stopp)
    if options.verbose > 0:
        print querystring
    cursor.execute(querystring)

    rows = cursor.fetchall()
    return rows
        
## --------------------------------------------------------------------------
def corrected_for_pressure(uncorrected, pressure_mbar):
    from math import exp
    
    press_0 = 1006.7

    corrected = uncorrected * exp(0.00721*(pressure_mbar-press_0))

    return corrected

## --------------------------------------------------------------------------
def corrected_for_efficiency(corrected):

    return corrected

## --------------------------------------------------------------------------
def main():
    print "This is the kiel2 module."

    (options, args) = parse_options("upload")
    if options.verbose > 1:
        print "options:", options
        print "args:", args
    if options.dryrun:
        print "dryrun: not sending any data to NMDB"

    station = "kiel2"
    data_type="1m"
    year = 2013
    month = 10
    day = 10
    #data = read_kiel2(options, station, data_type, year, month, day)
    #data = read_rev(options, station, data_type, year, month, day)
    data = read_rt(options, station, data_type, year, month, day)
    for line in data:
        print line

## --------------------------------------------------------------------------
if __name__ == '__main__':
    main()

